﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Diagnostics;
using System.Windows.Data;

namespace Odyssey.Controls
{
    [TemplateVisualState(Name = "Expanded", GroupName = "ExpansionStates")]
    [TemplateVisualState(Name = "Collapsed", GroupName = "ExpansionStates")]
    [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
    [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
    [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
    [TemplatePart(Name = partExpansionPanel, Type = typeof(ExpansionPanel))]
    public class DropDown : ListBox
    {
        const int maxItems = 5;
        const string partExpansionPanel = "PART_ExpansionPanel";

        private ExpansionPanel expansionPanel;

        public DropDown()
            : base()
        {
            base.DefaultStyleKey = typeof(DropDown);
            this.ItemContainerGenerator.ItemsChanged += new ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);
            IsEnabledChanged += new DependencyPropertyChangedEventHandler(OnEnabledChanged);
        }


        void OnEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!this.IsEnabled)
            {
                IsExpanded = false;
            }
            VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", true);
        }


        protected override void OnLostMouseCapture(MouseEventArgs e)
        {
            base.OnLostMouseCapture(e);
            IsExpanded = false;
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {

            base.OnLostFocus(e);
            DropDownItem item = FocusManager.GetFocusedElement() as DropDownItem;
            if (item == null || ItemContainerGenerator.IndexFromContainer(item) < 0)
            {
                IsExpanded = false;
            }
            VisualStateManager.GoToState(this, "Unfocused", true);
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            VisualStateManager.GoToState(this, "Focused", true);
        }


        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            DropDownItem lbItem = element as DropDownItem;
            lbItem.MouseLeftButtonUp += new MouseButtonEventHandler(OnItemClick);
        }

        void OnItemClick(object sender, MouseButtonEventArgs e)
        {
            IsExpanded ^= true;
        }

        /// <summary>
        /// Gets or sets whether the control is expanded.
        /// </summary>
        public bool IsExpanded
        {
            get { return (bool)GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsExpanded.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsExpandedProperty =
            DependencyProperty.Register("IsExpanded", typeof(bool), typeof(DropDown), new PropertyMetadata(false, OnExpandedPropertyChanged));

        private static void OnExpandedPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            DropDown dd = o as DropDown;
            dd.OnExpandedChanged((bool)e.OldValue, (bool)e.NewValue);
        }

        protected virtual void OnExpandedChanged(bool oldValue, bool newValue)
        {
            if (newValue)
            {
                SetSelectedItemState("SelectedAndExpanded");
            }
            else
            {
                if (SelectedIndex >= 0)
                {
                    SetSelectedItemState("Unselected");
                }
            }
            VisualStateManager.GoToState(this, newValue ? "Expanded" : "Collapsed", true);
        }

        private void SetSelectedItemState(string state)
        {
            DropDownItem item = ItemContainerGenerator.ContainerFromIndex(SelectedIndex) as DropDownItem;
            if (item != null) VisualStateManager.GoToState(item, state, true);
        }



        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            expansionPanel = GetTemplateChild(partExpansionPanel) as ExpansionPanel;
            UpdateItems();
            VisualStateManager.GoToState(this, IsExpanded ? "Expanded" : "Collapsed", false);
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is DropDownItem;
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new DropDownItem();
        }



        void ItemContainerGenerator_ItemsChanged(object sender, ItemsChangedEventArgs e)
        {
            if (Items.Count > maxItems) throw new IndexOutOfRangeException("Control does not support more than " + maxItems.ToString() + " items.");
            UpdateItems();
        }

        private void UpdateItems()
        {
            if (expansionPanel != null)
            {
                expansionPanel.Children.Clear();
                IItemContainerGenerator gen = ItemContainerGenerator;


                var pos = gen.GeneratorPositionFromIndex(0);
                using (gen.StartAt(pos, GeneratorDirection.Forward, true))
                {
                    bool isNew;
                    foreach (var item in Items)
                    {
                        FrameworkElement e0 = gen.GenerateNext(out isNew) as FrameworkElement;
                        if (e0 != null)
                        {
                            PrepareContainerForItemOverride(e0, item);
                            expansionPanel.Children.Add(e0);
                        }
                    }
                }
                expansionPanel.InvalidateArrange();
                expansionPanel.InvalidateMeasure();
            }
        }


    }
}
